package reflects

import "reflect"

type FuncInfo struct {
	Name        string         // 方法名
	InputTypes  []reflect.Type // 方法输入参数的类型
	OutputTypes []reflect.Type // 方法返回值类型
	Result      []any          // 方法返回值
}

func IterateMethod(entity any) (map[string]FuncInfo, error) {
	typ := reflect.TypeOf(entity)
	methodCounts := typ.NumMethod()
	res := make(map[string]FuncInfo, methodCounts)
	for i := 0; i < methodCounts; i++ {
		method := typ.Method(i)
		fn := method.Func
		numIn := fn.Type().NumIn()

		inputParamTypes := make([]reflect.Type, 0, numIn) // 方法的每一个参数的类型的集合
		inputValues := make([]reflect.Value, 0, numIn)    // 方法的每一个参数的值的集合
		numOut := fn.Type().NumOut()
		outputTypes := make([]reflect.Type, 0, numOut)

		// 方法的第一参数永远啊是接收器本身，所以需要提前加入
		inputValues = append(inputValues, reflect.ValueOf(entity))
		inputParamTypes = append(inputParamTypes, reflect.TypeOf(entity))

		// 遍历获取入参的集合
		for j := 1; j < numIn; j++ { // 因为第一个入参已(接收器本身)已经加入到集合中，所以从下标 1 开始即可
			fnInType := fn.Type().In(j)
			inputParamTypes = append(inputParamTypes, fnInType)
			inputValues = append(inputValues, reflect.Zero(fnInType)) // 将方法参数的 0 值添加进去
		}
		// 遍历获取输出类型
		for j := 0; j < numOut; j++ {
			outputTypes = append(outputTypes, fn.Type().Out(j))
		}
		// 反射调用该方法，获取结果
		resultValues := fn.Call(inputValues)
		result := make([]any, 0, len(resultValues))
		for _, v := range resultValues {
			result = append(result, v.Interface())
		}
		res[method.Name] = FuncInfo{
			Name:        method.Name,
			InputTypes:  inputParamTypes,
			OutputTypes: outputTypes,
			Result:      result,
		}
	}
	return res, nil
}
